<template>
    <div class="system-role" v-loading="isLoading">
        <!-- 组件文档请查阅: http://bearsee.com.cn/sibionics-ui-next/#/table -->
        <sib-table
            ref="sibTableRef"
            row-key="roleId"
            :search-config="searchConfig"
            :table-column="tableColumn"
            :request-config="requestConfig">
            <!-- 自定义插槽，插槽名称为对应列配置的 code -->
            <template #operate="{ row }">
                <el-button type="primary" link @click="handleEdit(row)">修改</el-button>
                <el-button type="primary" link @click="handleConfigure(row)">数据权限</el-button>
                <el-button type="danger" link @click="handleDelete(row)">删除</el-button>
            </template>
            <!-- 自定义表单与列表之间的内容 -->
            <template #operation-container>
                <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
                <el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
            </template>
        </sib-table>
        <el-dialog
            v-if="dialogConfig.visible"
            append-to-body
            draggable
            align-center
            v-model="dialogConfig.visible"
            :close-on-click-modal="false"
            :title="dialogConfig.title"
            :width="dialogConfig.width || '500px'">
            <sib-form
                class="role-dialog-form"
                reset-text="取消"
                :row-field-size="dialogConfig.rowFieldSize"
                :fields="dialogConfig.fields"
                :form="dialogConfig.form"
                @item-change="formItemChange"
                @reset="dialogConfig.visible = false"
                @submit="handleSubmit">
                <template #checkedKeys="{ form }">
                    <el-checkbox v-model="form.nodeExpand" @change="handleToogleExpand">展开/折叠</el-checkbox>
                    <el-checkbox v-model="form.nodeCheckAll" @change="handleToogleChecked">全选/全不选</el-checkbox>
                    <el-checkbox v-model="form.checkStrictly">父子联动</el-checkbox>
                    <sib-tree
                        ref="treeRef"
                        show-checkbox
                        :props="{ label: 'label' }"
                        :check-strictly="!form.checkStrictly"
                        :data="menus"
                        :selection="form.checkedKeys"></sib-tree>
                </template>
            </sib-form>
        </el-dialog>
    </div>
</template>

<script>
import { ref, reactive, inject } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';

export default {
    name: 'SystemRole',
    setup() {
        const axios = inject('$axios');
        const isLoading = ref(false);
        const sibTableRef = ref(null);
        // 查询模块表单配置
        const searchConfig = reactive({
            showExpand: false,
            rowFieldSize: 5,
            fields: [
                {
                    label: '角色名称',
                    code: 'roleName',
                    type: 'text',
                    maxlength: 100,
                },
                {
                    label: '权限字符',
                    code: 'roleKey',
                    type: 'text',
                    maxlength: 100,
                },
                {
                    label: '状态',
                    code: 'status',
                    type: 'select',
                    optionProps: { value: 'dictValue', label: 'dictLabel' },
                    requestConfig: {
                        url: 'common-status.json',
                        method: 'get',
                    },
                    options: [],
                },
                {
                    label: '创建时间',
                    code: 'daterange',
                    type: 'daterange',
                    startCode: 'beginTime',
                    endCode: 'endTime',
                    // 使用时间戳 valueFormat: 'x'
                    // valueFormat: 'x',
                },
            ],
        });
        // 表格表头配置
        const tableColumn = ref([
            {
                label: '角色名称',
                code: 'roleName',
                minWidth: 180,
            },
            {
                label: '权限字符',
                code: 'roleKey',
                minWidth: 180,
            },
            {
                label: '显示顺序',
                code: 'roleSort',
            },
            {
                label: '状态',
                code: 'status',
                type: 'switch',
                activeValue: '0',
                inactiveValue: '1',
                beforeChange: (value, { roleId }) => {
                    return new Promise((resolve, reject) => {
                        ElMessageBox.confirm(`请确认是否${String(value) === '0' ? '启用' : '停用'}该角色`, '温馨提示').then(() => {
                            axios.put('/role/changeStatus', { roleId, status: value }).then(() => {
                                ElMessage({ type: 'success', message: '操作成功' });
                                resolve();
                            }).catch(reject);
                        }).catch(reject);
                    });
                },
            },
            {
                label: '创建时间',
                code: 'createTime',
                type: 'timeStamp',
                format: 'YYYY-MM-DD hh:mm',
                minWidth: 160,
            },
            {
                label: '操作',
                code: 'operate',
                type: 'slot',
                minWidth: 180,
                fixed: 'right',
            },
        ]);
        // 列表查询接口配置
        const requestConfig = reactive({
            url: 'role-list.json',
            method: 'get',
            // 自定义传参
            customSearchParams: obj => {
                const params = {};
                Object.keys(obj).forEach(key => {
                    if ([0, false].includes(obj[key]) || obj[key]) params[key] = obj[key];
                });
                return params;
            },
        });

        // 新增、编辑等弹窗配置
        const dialogConfig = reactive({
            title: '',
            width: '500px',
            rowFieldSize: 1,
            // add/edit/data
            type: 'add',
            visible: false,
            // 新增、编辑的表单项配置
            editFields: [
                {
                    label: '角色名称',
                    code: 'roleName',
                    type: 'text',
                    maxlength: 100,
                    required: true,
                },
                {
                    label: '权限字符',
                    labelTips: '控制器中定义的权限字符，如：@PreAuthorize(`@ss.hasRole(\'admin\')`)',
                    code: 'roleKey',
                    type: 'text',
                    maxlength: 100,
                    required: true,
                },
                {
                    label: '角色顺序',
                    code: 'roleSort',
                    type: 'number',
                    controlsPosition: 'right',
                    required: true,
                },
                {
                    label: '状态',
                    code: 'status',
                    type: 'radio',
                    optionProps: { value: 'dictValue', label: 'dictLabel' },
                    requestConfig: {
                        url: 'common-status.json',
                        method: 'get',
                    },
                    options: [],
                    value: '0',
                    required: true,
                },
                {
                    label: '菜单权限',
                    code: 'checkedKeys',
                    type: 'slot',
                },
                {
                    label: '备注',
                    code: 'remark',
                    type: 'textarea',
                    maxlength: 500,
                },
            ],
            // 数据权限的表单项配置
            dataAuthorityFields: [
                {
                    label: '角色名称',
                    code: 'roleName',
                    type: 'text',
                    maxlength: 100,
                    disabled: true,
                    required: true,
                },
                {
                    label: '权限字符',
                    code: 'roleKey',
                    type: 'text',
                    maxlength: 100,
                    disabled: true,
                    required: true,
                },
                {
                    label: '权限范围',
                    code: 'dataScope',
                    type: 'select',
                    options: [
                        { value: '1', label: '全部数据权限' },
                        { value: '2', label: '自定数据权限' },
                        { value: '3', label: '本部门数据权限' },
                        { value: '4', label: '本部门及以下数据权限' },
                        { value: '5', label: '仅本人数据权限' },
                    ],
                    value: '1',
                    required: true,
                },
                {
                    label: '菜单权限',
                    code: 'checkedKeys',
                    type: 'slot',
                },
            ],
            fields: [],
            form: {},
        });
        // 菜单数据
        const menus = ref([]);
        const treeRef = ref(null);

        return {
            treeRef,
            isLoading,
            sibTableRef,
            searchConfig,
            tableColumn,
            requestConfig,
            dialogConfig,
            menus,
            handleAdd() {
                axios.get('menus-list.json').then(res => {
                    dialogConfig.fields = window.SIB.deepCopy(dialogConfig.editFields);
                    dialogConfig.form = { menuCheckStrictly: true };
                    menus.value = (res.data || {}).data || [];
                    dialogConfig.type = 'add';
                    dialogConfig.title = '新增角色';
                    dialogConfig.visible = true;
                });
            },
            handleEdit(row) {
                dialogConfig.type = 'edit';
                dialogConfig.title = '编辑角色';
                axios.get('menus-list.json').then(res => {
                    const checkedKeys = res.checkedKeys || [];
                    menus.value = (res.data || {}).data || [];
                    dialogConfig.fields = window.SIB.deepCopy(dialogConfig.editFields);
                    dialogConfig.form = { ...row, checkStrictly: row.menuCheckStrictly, checkedKeys };
                    dialogConfig.visible = true;
                }).finally(() => {
                    isLoading.value = false;
                });
            },
            handleToogleExpand(checked) {
                menus.value.forEach(menu => {
                    treeRef.value.treeRef.store.nodesMap[menu.id].expanded = checked;
                });
            },
            handleToogleChecked(checked) {
                treeRef.value.setCheckedNodes((checked && menus.value) || []);
            },
            handleConfigure(row) {
                isLoading.value = true;
                dialogConfig.type = 'data';
                dialogConfig.title = '编辑数据权限';
                axios.get('department-list.json').then(res => {
                    const checkedKeys = res.checkedKeys || [];
                    menus.value = (res.data || {}).data || [];
                    dialogConfig.fields = window.SIB.deepCopy(dialogConfig.dataAuthorityFields);
                    dialogConfig.form = { ...row, checkStrictly: row.deptCheckStrictly, checkedKeys };
                    dialogConfig.visible = true;
                }).finally(() => {
                    isLoading.value = false;
                });
            },
            formItemChange(data, field) {
                if (dialogConfig.type === 'data' && field.code === 'dataScope') {
                    const treeField = dialogConfig.fields.find(({ code }) => code === 'checkedKeys');
                    treeField.show = data.value === '2';
                }
            },
            handleDelete(row) {
                ElMessageBox.confirm(`是否删除【${row.roleName}】`, '温馨提示').then(() => {
                    axios.delete(`/role/${row.roleId}`).then(() => {
                        ElMessage({ type: 'success', message: '删除成功' });
                        sibTableRef.value.getTableData();
                    });
                }).catch(() => {});
            },
            handleSubmit(form, cb) {
                let checkedKeys = [];
                if (treeRef.value) {
                    // 目前被选中的菜单节点
                    checkedKeys = treeRef.value.getCheckedKeys();
                    // 半选中的菜单节点
                    const halfCheckedKeys = treeRef.value.getHalfCheckedKeys();
                    checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
                }
                const requestObj = {
                    add: {
                        url: '/role',
                        method: 'post',
                        params: { ...form, menuIds: checkedKeys, menuCheckStrictly: form.checkStrictly },
                        validator: () => {
                            if (form.roleKey !== 'admin' && !checkedKeys.length) {
                                ElMessage({ type: 'warning', message: '请选择菜单权限' });
                                cb();
                                return false;
                            }
                            return true;
                        },
                    },
                    edit: {
                        url: '/role',
                        method: 'put',
                        params: { ...form, menuIds: checkedKeys, menuCheckStrictly: form.checkStrictly },
                        validator: () => {
                            if (form.roleKey !== 'admin' && !checkedKeys.length) {
                                ElMessage({ type: 'warning', message: '请选择菜单权限' });
                                cb();
                                return false;
                            }
                            return true;
                        },
                    },
                    data: {
                        url: '/role/dataScope',
                        method: 'put',
                        params: { ...form, deptIds: form.dataScope === '2' ? checkedKeys : [], deptCheckStrictly: form.checkStrictly },
                        validator: () => true,
                    },
                };
                const { url, method, params, validator } = requestObj[dialogConfig.type];
                if (!validator()) return;
                axios[method](url, params).then(() => {
                    dialogConfig.visible = false;
                    sibTableRef.value.getTableData();
                }).finally(cb);
            },
            handleExport() {
                isLoading.value = true;
                axios.post('/role/export', sibTableRef.value.searchParams || {}, { responseType: 'blob' }).then(res => {
                    window.SIB.download(res, `role_${new Date().getTime()}.xlsx`);
                    ElMessage({ type: 'success', message: '导出成功' });
                }).finally(() => {
                    isLoading.value = false;
                });
            },
        };
    },
};
</script>

<style lang="scss">
.system-role {
    .sib-table {
        height: 100%;
    }
}

.role-dialog-form {
    .sib-form-item__checkedKeys {
        .sib-tree {
            width: 100%;
            height: 200px;
            padding: 10px 0;
        }
    }
}
</style>
